home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / install / rawwrite / rawrite2.c < prev    next >
C/C++ Source or Header  |  1996-11-17  |  12KB  |  453 lines

  1. /*
  2.  rawrite.c    Write a binary image to a diskette.
  3.         Originally by Mark Becker
  4.  
  5.  Heavily modified by Guy Helmer (4/29/91) to improve performance and
  6.  add features.
  7.  
  8.  Compiling:
  9.     Appeared to have been written for Turbo C, so I've surrounded
  10.     compiler-specific code in "#if defined(__TURBOC__)" and added
  11.     code in the "#else" clauses for Microsoft C.  Under MSC, code
  12.     should be compiled in the Large memory model.
  13.  
  14.  Usage:
  15.     MS-DOS prompt> RAWRITE
  16.         and follow the prompts, -or-
  17.  
  18.     MS-DOS prompt> RAWRITE [-f <file>] [-d <drive>] [-n(owait)] [-h(elp)]
  19.         where:    -f <file> - name of disk image file
  20.             -d <drive> - diskette drive to use, must be A or B
  21.             -n - don't prompt for user to insert diskette
  22.             -h - print usage information to stdout
  23.  
  24. History
  25. -------
  26.  
  27.   1.0    -    Initial release
  28.   1.1    -    Beta test (fixing bugs)                4/5/91
  29.           Some BIOS's don't like full-track writes.
  30.   1.101    -    Last beta release.                4/8/91
  31.           Fixed BIOS full-track write by only
  32.         writing 3 sectors at a time.
  33.   1.2    -    Final code and documentation clean-ups.        4/9/91
  34.   2.0 (ghelmer@dsuvax.dsu.edu)                    4/30/92
  35.       -    Performance improvements
  36.         Added command line options
  37.         Now compiles under Microsoft C (version 5.1)
  38.  
  39. Version 2.0 Copyright 1992 Guy Helmer
  40.     Permission to use, copy, modify, and distribute this software and
  41. its documentation for any purpose and without fee is hereby granted,
  42. provided that the above copyright notice appears in all copies and
  43. that both the above copyright notice and this permission notice appear
  44. in supporting documentation.  This software is made available "as is",
  45. and
  46. GUY HELMER DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, WITH
  47. REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  48. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
  49. AND IN NO EVENT SHALL GUY HELMER BE LIABLE FOR ANY SPECIAL, INDIRECT
  50. OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
  51. OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  52. (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN
  53. CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  54.  
  55. */
  56.  
  57. #if defined(__TURBOC__)
  58. #include <alloc.h>
  59. #include <dir.h>
  60. #else
  61. #include <malloc.h>
  62. #endif
  63. #include <bios.h>
  64. #include <dos.h>
  65. #include <io.h>
  66. #include <fcntl.h>
  67. #include <signal.h>
  68. #include <stdio.h>
  69. #include <stdlib.h>
  70. #include <string.h>
  71.  
  72. #define FALSE    0
  73. #define TRUE    (!FALSE)
  74.  
  75. #define SECTORSIZE    512
  76. #if !defined(__TURBOC__)
  77. #define MAXPATH _MAX_PATH
  78. #endif
  79.  
  80. #if defined(__TURBOC__)
  81. /*
  82.   BIOS Disk Function Commands
  83.   */
  84. #define    RESET    0
  85. #define    LAST    1
  86. #define    READ    2
  87. #define    WRITE    3
  88. #define    VERIFY    4
  89. #define    FORMAT    5
  90. #else
  91. /*
  92.   Microsoft C
  93.   */
  94. #define RESET  _DISK_RESET
  95. #define LAST   _DISK_STATUS
  96. #define READ   _DISK_READ
  97. #define WRITE  _DISK_WRITE
  98. #define VERIFY _DISK_VERIFY
  99. #define FORMAT _DISK_FORMAT
  100.  
  101. static unsigned biosdisk(unsigned, unsigned, unsigned, unsigned, unsigned,
  102.     unsigned, void far *);
  103.  
  104. static unsigned
  105. biosdisk(service, drive, head, track, sector, nsectors, buffer)
  106.      unsigned service;
  107.      unsigned drive;
  108.      unsigned head;
  109.      unsigned track;
  110.      unsigned sector;
  111.      unsigned nsectors;
  112.      void far *buffer;
  113. {
  114.   struct diskinfo_t diskinfo;
  115.  
  116.   diskinfo.drive = drive;
  117.   diskinfo.head = head;
  118.   diskinfo.track = track;
  119.   diskinfo.sector = sector;
  120.   diskinfo.nsectors = nsectors;
  121.   diskinfo.buffer = buffer;
  122.  
  123.   return (_bios_disk(service, &diskinfo) >> 8);
  124. }
  125. #endif
  126.  
  127. int done;
  128.  
  129. #if defined(__TURBOC__)
  130. /*
  131.  Catch ^C and ^Break.
  132. */
  133. int
  134. handler(void)
  135. {
  136.   done = TRUE;
  137.   return(0);
  138. }
  139. #else
  140. int
  141. handler(void)
  142. {
  143.   signal(SIGINT, SIG_IGN);
  144.   done = TRUE;
  145.   signal(SIGINT, handler);
  146.   return(0);
  147. }
  148. #endif
  149.  
  150. static void
  151. msg(char (*s))
  152. {
  153.   fprintf(stderr, "%s\n", s);
  154.   _exit(1);
  155. }
  156.  
  157. /*
  158.   Identify the error code with a real error message.
  159.   */
  160. void
  161. Error(int (status))
  162. {
  163.   switch (status)
  164.     {
  165.     case 0x00:    msg("Operation Successful");                break;
  166.     case 0x01:    msg("Bad command");                    break;
  167.     case 0x02:    msg("Address mark not found");                break;
  168.     case 0x03:    msg("Attempt to write on write-protected disk");    break;
  169.     case 0x04:    msg("Sector not found");                break;
  170.     case 0x05:    msg("Reset failed (hard disk)");            break;
  171.     case 0x06:    msg("Disk changed since last operation");        break;
  172.     case 0x07:    msg("Drive parameter activity failed");            break;
  173.     case 0x08:    msg("DMA overrun");                    break;
  174.     case 0x09:    msg("Attempt to DMA across 64K boundary");        break;
  175.     case 0x0A:    msg("Bad sector detected");                break;
  176.     case 0x0B:    msg("Bad track detected");                break;
  177.     case 0x0C:    msg("Unsupported track");                break;
  178.     case 0x10:    msg("Bad CRC/ECC on disk read");            break;
  179.     case 0x11:    msg("CRC/ECC corrected data error");            break;
  180.     case 0x20:    msg("Controller has failed");                break;
  181.     case 0x40:    msg("Seek operation failed");                break;
  182.     case 0x80:    msg("Attachment failed to respond");            break;
  183.     case 0xAA:    msg("Drive not ready (hard disk only");            break;
  184.     case 0xBB:    msg("Undefined error occurred (hard disk only)");    break;
  185.     case 0xCC:    msg("Write fault occurred");                break;
  186.     case 0xE0:    msg("Status error");                    break;
  187.     case 0xFF:    msg("Sense operation failed");                break;
  188.     }
  189.   _exit(1);
  190. }
  191.  
  192. /*
  193.  Identify what kind of diskette is installed in the specified drive.
  194.  Return the number of sectors per track assumed as follows:
  195.  9    -    360 K and 720 K 5.25".
  196. 15    -    1.2 M HD    5.25".
  197. 18    -    1.44 M        3.5".
  198. */
  199. int
  200. nsects(int (drive))
  201. {
  202.   static int nsect[] = {18, 15, 9};
  203.  
  204. #if defined(__TURBOC__)
  205.   char *buffer;
  206. #else
  207.   char far *buffer;
  208. #endif
  209.   int i, status;
  210.  
  211. /*
  212.  Read sector 1, head 0, track 0 to get the BIOS running.
  213. */
  214. #if defined(__TURBOC__)
  215.   buffer = (char *)malloc(SECTORSIZE);
  216. #else
  217.   buffer = (char far *)_fmalloc(SECTORSIZE);
  218. #endif
  219.   biosdisk(RESET, drive, 0, 0, 0, 0, buffer);
  220.   status = biosdisk(READ, drive, 0, 10, 1, 1, buffer);
  221.   if (status == 0x06)            /* Door signal change?    */
  222.     status = biosdisk(READ, drive, 0, 0, 1, 1, buffer);
  223.  
  224.   for (i = 0; i < sizeof(nsect) / sizeof(int); ++i)
  225.     {
  226.       biosdisk(RESET, drive, 0, 0, 0, 0, buffer);
  227.       status = biosdisk(READ, drive, 0, 0, nsect[i], 1, buffer);
  228.       if (status == 0x06)
  229.     status = biosdisk(READ, drive, 0, 0, nsect[i], 1, buffer);
  230.       if (status == 0x00)
  231.     break;
  232.     }
  233. #if defined(__TURBOC__)
  234.   free(buffer);
  235. #else
  236.   _ffree(buffer);
  237. #endif
  238.  
  239.   if (i == sizeof(nsect)/sizeof(int))
  240.     {
  241.       msg("Can't figure out how many sectors/track for this diskette.");
  242.     }
  243.   return(nsect[i]);
  244. }
  245.  
  246. void
  247. main(argc, argv)
  248.      int argc;
  249.      char *argv[];
  250. {
  251.   char fname[MAXPATH], drvtmp[4];
  252.   char far *buffer, far *bufbase;
  253.   int count, fdin, drive, head, track, status, spt, buflength, ns;
  254.   unsigned long addrtmp;
  255.   int fname_spec, drive_spec, no_wait, i;
  256.  
  257.   done = 0;
  258.   fname_spec = 0;
  259.   drive_spec = 0;
  260.   no_wait = 0;
  261.  
  262.   puts("RaWrite 2.0 - Write disk file to raw floppy diskette\n");
  263. #if defined(__TURBOC__)
  264.   ctrlbrk(handler);
  265. /* #else
  266.   Install Microsoft SIGINT handler later in the routine,
  267.   ie. after any user input has completed.
  268.   */
  269. #endif
  270.   for (i = 1; i < argc; i++)
  271.     {
  272.       /* Check each argument for valid options. */
  273.       if (*argv[i] == '-')
  274.     {
  275.       switch (argv[i][1])
  276.         {
  277.         case 'f':
  278.           if (i + 1 < argc)
  279.         {
  280.           strncpy(fname, argv[i + 1], sizeof(fname) - 1);
  281.           fname[sizeof(fname) - 1] = '\0';
  282.           fname_spec = TRUE;
  283.           i++;
  284.         }
  285.           else
  286.         {
  287.           fprintf(stderr, "filename must follow -f option\n");
  288.           exit(1);
  289.         }
  290.           break;
  291.         case 'd':
  292.           if (i + 1 < argc)
  293.         {
  294.           drvtmp[0] = *argv[i + 1];
  295.           drvtmp[1] = '\0';
  296.           drive_spec = TRUE;
  297.           i++;
  298.         }
  299.           else
  300.         {
  301.           fprintf(stderr, "drive letter must follow -d option\n");
  302.           exit(1);
  303.         }
  304.           break;
  305.         case 'n':
  306.           no_wait = TRUE;
  307.           break;
  308.         case 'h':
  309.           puts("\nRAWRITE option information:\n");
  310.           puts("\t-f <file>: specify disk image file");
  311.           puts("\t-d <drive>: specify diskette drive to use;");
  312.           puts("\t\tmust be either A or B");
  313.           puts("\t-n: don't wait for user to insert diskette --");
  314.           puts("\t\tassumes diskette is waiting in selected drive");
  315.           puts("\t-h: print this help message and exit\n");
  316.           exit(1);
  317.           break;
  318.         default:
  319.           fprintf(stderr, "rawrite: '%s' - unknown option.\n", argv[i]);
  320.           exit(1);
  321.         }
  322.     }
  323.       else
  324.     {
  325.       fprintf(stderr, "rawrite: '%s' - unknown option.\n", argv[i]);
  326.       fprintf(stderr, "Use 'rawrite -h' for instructions.\n");
  327.       exit(1);
  328.     }
  329.     }
  330.   if (!fname_spec)
  331.     {
  332.       printf("Enter disk image source file name: ");
  333.       fgets(fname, sizeof(fname), stdin);
  334.       if (strchr(fname, '\n') != (char *) NULL)
  335.     *(strchr(fname, '\n')) = '\0';
  336.     }
  337.   _fmode = O_BINARY;
  338.   if ((fdin = open(fname, O_RDONLY)) < 0)
  339.     {
  340.       perror(fname);
  341.       exit(1);
  342.     }
  343.   if (done)
  344.     exit(1);
  345.  
  346.   if (!drive_spec)
  347.     {
  348.       printf("Enter target diskette drive: ");
  349.       fgets(drvtmp, sizeof(drvtmp), stdin);
  350.       if (strchr(drvtmp, '\n') != (char *) NULL)
  351.     *(strchr(drvtmp, '\n')) = '\0';
  352.     }
  353.   strupr(drvtmp);
  354.   if (strlen(drvtmp) == 0 || drvtmp[0] < 'A' || drvtmp[0] > 'B')
  355.     {
  356.       fprintf(stderr, "Drive was '%s'; must be A or B.\n", drvtmp);
  357.       exit(1);
  358.     }
  359.   if (done)
  360.     exit(1);
  361.   drive = drvtmp[0] - 'A';
  362.   if (!no_wait)
  363.     {
  364.       printf("Please insert a formatted diskette into ");
  365.       printf("drive %c: and press -ENTER- :", drive + 'A');
  366. #if defined(__TURBOC__)
  367.       while (bioskey(1) == 0) ;                /* Wait...    */
  368.       if ((bioskey(0) & 0x7F) == 3) exit(1);        /* Check for ^C    */
  369. #else
  370.       if ((_bios_keybrd(_KEYBRD_READ) & 0xff) == 0x03)
  371.     /* Exit if Ctrl-C was pressed. */
  372.     exit(1);
  373. #endif
  374.       putchar('\n');
  375.     }
  376.   if (done)
  377.     exit(1);
  378.  
  379. #if !defined(__TURBOC__)
  380. /*
  381.   Install Microsoft C SIGINT (Ctrl-C) handler.
  382.   */
  383.   signal(SIGINT, handler);
  384. #endif
  385.  
  386. /*
  387.  * Determine number of sectors per track and allocate buffers.
  388.  */
  389.   spt = nsects(drive);
  390.   buflength = spt * SECTORSIZE;
  391.   /*
  392.     Allocate double the necessary space to make the 64K DMA boundary
  393.     adjustment easy.
  394.     */
  395. #if defined(__TURBOC__)
  396.   buffer = (char *)malloc(buflength * 2);
  397.   if (buffer == (char *) NULL)
  398. #else
  399.   buffer = (char far *)_fmalloc(buflength * 2);
  400.   if (buffer == (char far *) NULL)
  401. #endif
  402.     {
  403.       fprintf(stderr, "Couldn't allocate track buffer\n");
  404.       exit(1);
  405.     }
  406.   bufbase = buffer;
  407. /*
  408.   Now mangle the buffer base address to avoid physical 64Kb boundary
  409.   problems with DMA.  If the end of the track buffer is not in the same
  410.   physical 64Kb block as the start of the buffer, then start the track
  411.   buffer in the second half of our allocated memory.
  412.   */
  413.   addrtmp = (((unsigned long)FP_SEG(bufbase)) << 4) + FP_OFF(bufbase);
  414. #if defined(DEBUG)
  415.   printf("Physical address of buffer base = %8.8lX\n", addrtmp);
  416. #endif
  417.   if ((addrtmp + (unsigned long)buflength) & 0xffff0000L !=
  418.        addrtmp & 0xffff0000L)
  419.     {
  420.       /*
  421.     Use the second half of the buffer.  This will work until
  422.     diskette tracks exceed 64 sectors, which shouldn't be in the
  423.     near future.
  424.     */
  425.       bufbase += buflength;
  426.     }
  427.   printf("Number of sectors per track for this disk is %d\n", spt);
  428.   printf("Writing image to drive %c:.  Press ^C to abort.\n", drive + 'A');
  429.  
  430. /*
  431.  * Start writing data to diskette until there is no more data to write.
  432.  */
  433.  
  434.   head = track = 0;
  435.   while ((count = read(fdin, bufbase, buflength)) > 0 && !done)
  436.     {
  437.       printf("Track: %02d  Head: %2d\r", track, head);
  438.       status = biosdisk(WRITE, drive, head, track, 1, spt, bufbase);
  439.  
  440.       if (status != 0)
  441.     Error(status);
  442.  
  443.       if ((head = (head + 1) & 1) == 0)
  444.     ++track;
  445.     }
  446.   if (eof(fdin))
  447.     {
  448.       printf("\nDone.\n");
  449.       biosdisk(READ, drive, 0, 0, 1, 1, buffer);        /* Retract head    */
  450.     }
  451.   exit(0);
  452. }    /* end main */
  453.